#pragma once
#include <iostream>
#include <sys/stat.h>
#include <fstream>
#include <vector>
#include <experimental/filesystem>
#include <jsoncpp/json/json.h>
#include <memory>
#include <sstream>
#include "bundle.h"
namespace Cloud
{
    namespace fs = std::experimental::filesystem;
    class FileUtil
    {
    private:
        const std::string _filename;

    public:
        FileUtil(const std::string &filename) : _filename(filename){};
        // 获取文件大小
        int64_t FileSize()
        {
            struct stat fstat;
            if (stat(_filename.c_str(), &fstat) < 0)
            {
                std::cerr << "get file size failed!" << std::endl;
                return -1;
            }
            return fstat.st_size;
        }
        // 获取文件最后一次修改的时间
        time_t LastMTime()
        {
            struct stat fstat;
            if (stat(_filename.c_str(), &fstat) < 0)
            {
                std::cerr << "get file last modify time failed!" << std::endl;
                return -1;
            }
            return fstat.st_mtime;
        }
        // 获取最后一次访问时间
        time_t LastAtime()
        {
            struct stat fstat;
            if (stat(_filename.c_str(), &fstat) < 0)
            {
                std::cerr << "get file last access time failed!" << std::endl;
                return -1;
            }
            return fstat.st_atime;
        }
        // 获取文件名
        std::string FileName()
        {
            size_t pos = _filename.find_last_of('/');
            if (pos == std::string::npos)
            {
                return _filename;
            }
            return _filename.substr(pos + 1);
        }
        // 向文件写入数据
        bool SetContent(const std::string &body)
        {
            std::ofstream ofs;
            ofs.open(_filename, std::ios_base::binary);
            if (ofs.is_open() == false)
            {
                std::cerr << "write file open failed!" << std::endl;
                return false;
            }
            ofs.write(body.c_str(), body.size());
            if (ofs.good() == false)
            {
                std::cerr << "write file open failed!" << std::endl;
                ofs.close();
                return false;
            }
            ofs.close();
            return true;
        }
        // 获取文件指定位置开始的指定长度数据
        bool GetPosLen(std::string *body, size_t pos, size_t len)
        {
            if ((int64_t)(pos + len) > this->FileSize())
            {
                std::cerr << "get file length failed!" << std::endl;
                return false;
            }
            std::ifstream ifs;
            ifs.open(_filename, std::ios::binary);
            if (ifs.is_open() == false)
            {
                std::cerr << "read open file failed!" << std::endl;
                return false;
            }
            ifs.seekg(pos, std::ios::beg);
            body->resize(len);
            ifs.read(&(*body)[0], len);
            if (ifs.good() == false)
            {
                std::cerr << "get file content failed" << std::endl;
                ifs.close();
                return false;
            }
            ifs.close();
            return true;
        }
        bool GetContent(std::string *body)
        {
            return GetPosLen(body, 0, this->FileSize());
        }
        // 判断文件是否存在
        bool Exists()
        {
            return fs::exists(_filename);
        }
        // 创建目录
        bool CreateDir()
        {
            if (this->Exists())
            {
                return true;
            }
            return fs::create_directories(_filename);
        }
        // 遍历目录，获取目录下的所有文件(绝对路径)
        bool ScanDir(std::vector<std::string> *arr)
        {
            for (auto &file : fs::directory_iterator(_filename))
            {
                if (fs::is_directory(file) == true)
                {
                    continue;
                }
                // relative_path 带有路径的文件名
                arr->push_back(fs::path(file).relative_path().string());
            }
            return true;
        }
        // 压缩
        bool Compress(const std::string &packname)
        {
            // 获取原文件数据
            std::string body;
            if (GetContent(&body) == false)
            {
                std::cerr << "compress data get file content failed!" << std::endl;
                return false;
            }
            // 对原文件数据进行压缩
            std::string packed = bundle::pack(bundle::LZIP, body);
            // 将压缩数据存放到压缩包内
            FileUtil fu(packname);
            if (fu.SetContent(packed) == false)
            {
                std::cerr << "compress data write failed!" << std::endl;
                return false;
            }
            return true;
        }
        // 解压缩
        bool UnCompress(const std::string &newfile)
        {
            // 提取压缩数据
            std::string body;
            if (GetContent(&body) == false)
            {
                std::cerr << "uncompress data get file content failed1" << std::endl;
                return false;
            }
            // 对原数据进行解压
            std::string unpacked = bundle::unpack(body);
            // 将解压后的数据存放的新的文件中
            FileUtil fu(newfile);
            if (fu.SetContent(unpacked) == false)
            {
                std::cerr << "uncompress data write failed!" << std::endl;
                return false;
            }
            return true;
        }
        // 删除文件
        bool Remove()
        {
            if (Exists() == false)
            {
                return true;
            }
            return remove(_filename.c_str()) == 0 ? true : false;
        }
    };

    class JsonUtil
    {
    public:
        // 序列化
        static bool Serialize(const Json::Value &root, std::string *str)
        {
            Json::StreamWriterBuilder swb;
            std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
            std::stringstream ss;
            if (sw->write(root, &ss) != 0)
            {
                std::cerr<<"Serialize write failed!"<<std::endl;
                return false;
            }
            *str = ss.str();
            return true;
        }
        // 反序列化
        static bool Deserialize(const std::string &str, Json::Value *root)
        {
            Json::CharReaderBuilder crb;
            std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
            std::string err;
            if (cr->parse(str.c_str(), str.c_str() + str.size(), root, &err) == false)
            {
                std::cerr<<"Deserialize parse error:"<<err<<std::endl;
                return false;
            }
            return true;
        }
    };
}
